package com.devbobcorn.nekoration.sounds.music;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.*;

import javax.annotation.Nullable;

import com.devbobcorn.nekoration.sounds.ModSounds;

import net.minecraft.client.Minecraft;

public final class LyricsHelper {
	private static final String lineString = "\\[([0-9]+),([0-9]+)\\](.*)";
	private static final Pattern linePattern = Pattern.compile(lineString);
	private static final String wordString = "<([0-9]+),([0-9]+),([0-9]+)>([^<>]*)";
	private static final Pattern wordPattern = Pattern.compile(wordString);
    private static final String translationString = "\\[language:([A-Za-z0-9\\/+=]+)\\]";
	private static final Pattern translationPattern = Pattern.compile(translationString);

    public static class Lyrics {
        public final List<Line> lines = new ArrayList<>();
        public int lineCount = 0;
        public final boolean[] hasKey = new boolean[ModSounds.MAX_FRAME];
        public final Map<Integer, LinePiece> timeMap = new HashMap<>();

        private void ProcessLine(String text){
            Matcher t = translationPattern.matcher(text);
            if (t.matches()){
                String lang = t.group(1);
                Base64.Decoder b64Decoder = Base64.getDecoder();
                System.out.println(b64Decoder.decode(lang));
            }
            Matcher ln = linePattern.matcher(text);
            if (ln.matches()){
                // Process a line...
                int lineStart = Integer.parseInt(ln.group(1));
                int lineDuration = Integer.parseInt(ln.group(2));

                String words = ln.group(3);
                Matcher w = wordPattern.matcher(words);
                String curText = "";
                Line curLine = new Line(++this.lineCount, lineStart, lineDuration, this);
                while (w.find()){ // Process a word...
                    String word = w.group(4);
                    curLine.words.add(new Word(lineStart + Integer.parseInt(w.group(1)), Integer.parseInt(w.group(2)), curText, w.group(4), curLine));
                    curText += word;
                }
                // Store full text of this line...
                curLine.full = curText;
                lines.add(curLine);
            }
        }

        public Lyrics(File source){
            try {
                if (source.exists()){
                    InputStreamReader isr = new InputStreamReader(new FileInputStream(source), "utf-8");
                    BufferedReader br = new BufferedReader(isr);
                    String line = "";
                    while ((line = br.readLine()) != null){
                        ProcessLine(line);
                    }
                    br.close();
                } else {
                    System.err.println("File not found!");
                }
            } catch (Exception e){
                e.printStackTrace();
            }
        }

        public Lyrics(String source){
            for (String line : source.split("\r\n")){
                ProcessLine(line);
            }
        }

        @Nullable
        public LinePiece getAtTime(int current, int target){
            for (int i = target;i >= current;i--){ // Go through every frame backwards...
                if (hasKey[i]) {
                    LinePiece piece = timeMap.get(i);
                    return piece;
                }
            }
            return null;
        }

        public String toString(){
            String result = "";
            for (Line line : lines){
                result += line;
            }
            return result;
        }
    }

    public static class Line {
        public final int index;
        public final int start;
        public final int duration;
        public String full;
        public String translation;
        public final List<Word> words;
        public final Lyrics lyrics;

        public Line(int index, int start, int duration, Lyrics lyrics){
            this.index = index;
            this.start = start;
            this.duration = duration;
            this.words = new ArrayList<>();
            this.lyrics = lyrics;
        }

        public int getEndTime(){
            return start + duration;
        }

        public String toString(){
            String result = "";
            for (Word word : words){
                result += word;
            }
            return result;
        }
    }

    public static class Word {
        public final int start;
        public final int duration;
        public final String prevText;
        public final String text;
        private final Line line;

        public Word(int start, int duration, String prev, String text, Line line){
            this.start = start;
            this.duration = duration;
            this.prevText = prev;
            this.text = text;
            this.line = line;

            // Prepare TimeMap... TODO Complete
            this.line.lyrics.hasKey[start] = true;
            this.line.lyrics.timeMap.put(start, new LinePiece(prev, text, line, this));
        }

        public String toString(){
            return "[" + start + "," + duration + "]" + text;
        }
    }

    public static class LinePiece {
        public final String prev; // Previous Text...
        public final String piece; // Played Part...
        public final Line line; // Rest of this Line
        public final Word word; // Current Word...

        public LinePiece(String text, String piece, Line line, Word word){
            this.prev = text;
            this.piece = piece;
            this.line = line;
            this.word = word;
        }

        public String getRest(){
            return line.full.substring(prev.length() + piece.length());
        }
    }

    public static Lyrics lyrics;
    public static boolean ready = false;

    @SuppressWarnings("resource")
    public static void load(String name){
        // Load the lyrics file...
        File txtFile = new File(Minecraft.getInstance().gameDirectory, "nekomusic/" + name + ".txt");
        if (txtFile.exists()){
            try {
                System.out.println("Loading txt lyrics...");
                lyrics = new Lyrics(txtFile);
                ready = true;
                return;
            } catch (Exception e){
                e.printStackTrace();
            }
        } else { // Check krc file...
            File krcFile = new File(Minecraft.getInstance().gameDirectory, "nekomusic/" + name + ".krc");
            if (krcFile.exists()){
                try {
                    System.out.println("Loading krc lyrics...");
                    lyrics = new Lyrics(LyricsDecoder.decode(krcFile));
                    ready = true;
                    return;
                } catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
        ready = false;
    }
}
